home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / dev / misc / psgrind.lha / pfontedp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-11  |  19.7 KB  |  847 lines

  1. /* pfontedpr - general purpose "pretty printer".
  2.  *
  3.  * This version is a hacked up version of tfontedpr.c as obtained from
  4.  * the following people
  5.  *
  6.  * Copyright (C) 1985 by Van Jacobson, Lawrence Berkeley Laboratory.
  7.  * This program may be freely used and copied but may not be sold
  8.  * without the author's written permission.  This notice must remain
  9.  * in any copy or derivative.
  10.  *
  11.  * This program is used as part of the "tgrind" shell script.  It
  12.  * converts program source file(s) to TeX input files.
  13.  *
  14.  * This program is an adaptation of "vfontedpr" v4.2 (12/11/84) from
  15.  * the 4.2bsd Unix distribution.  Vfontedpr was written by Dave
  16.  * Presotto (based on an earlier program of the same name written by
  17.  * Bill Joy).
  18.  *
  19.  * I would welcome comments, enhancements, bug fixes, etc.  Please 
  20.  * mail them to:
  21.  *    van@lbl-rtsg.arpa    (from arpanet, milnet, csnet, etc.)
  22.  *    ..!ucbvax!lbl-csam!van    (from Usenet/UUCP)
  23.  *
  24.  * Modifications.
  25.  * --------------
  26.  *  8Apr93  Dylan McNamee (dylan@cs.washington.edu)  
  27.  *            Modernized the code.  Now passes ANSI without warnings.
  28.  *            -o option added
  29.  * 30Mar85  Chris & Van: Fixed "\C" & "\S" (comment & string start indicators)
  30.  *            to really appear at the start of comments & strings.
  31.  *            Changes for speeded-up expmatch.
  32.  * 29Mar85  Chris Torek (chris@maryland):  Bug fixes for '~' and '^L'
  33.  *            output.  Most cpu-time eaters recoded to improve
  34.  *            efficiency.
  35.  * 10Feb85  Van        Written.
  36.  */
  37.  
  38. #include <stdio.h>
  39. #include <ctype.h>
  40.  
  41. #include    <stdlib.h>
  42. #include    <string.h>
  43. #include    <time.h>
  44. #ifdef    MSDOS
  45. extern char     *asctime();
  46. #else
  47.  
  48. #include    <sys/types.h>
  49. #include    <sys/stat.h>
  50. #endif
  51.  
  52. #define    DBUFSIZ    2048
  53. #define boolean int
  54. #define TRUE 1
  55. #define FALSE 0
  56. #define NIL 0
  57. #define STANDARD 0
  58. #define ALTERNATE 1
  59.  
  60. #define STRLEN 10        /* length of strings introducing things */
  61. #define PNAMELEN 80        /* length of a function/procedure name */
  62. #define PSMAX 20        /* size of procedure name stacking */
  63.  
  64. /* regular expression routines */
  65.  
  66. char    *expmatch(char *, char *, char **, char *);        
  67.                 /* match a string to an expression */
  68. char    *convexp(char *);    /* convert expression to internal form */
  69. char    *tgetstr();
  70. void    putstr(char *cp);
  71. int     tgetent(char *, char *, char *);
  72. char    *tgetstr(char *, char **);
  73. int     tgetflag(char *);
  74. void    sinitfile(void);
  75. void    outchar(char c);
  76. int     outpsstring(char *);
  77. void    putKcp(char *, char *, boolean);
  78. void    putScp(char *);
  79. boolean    isproc(char *);
  80. int     width(char *, char *);
  81. int     iskw(char *);
  82. int     modechange(int);
  83. void    charmode(void);
  84.  
  85. /*
  86.  *    The state variables
  87.  */
  88.  
  89. #define    _SMODE    1
  90. #define    _SHMODE    2
  91. #define    _KMODE    3
  92. #define    _CMODE    4
  93. #define    _NMODE    5
  94.  
  95. boolean    incomm;            /* in a comment of the primary type */
  96. boolean    instr;            /* in a string constant */
  97. boolean    inchr;            /* in a string constant */
  98. boolean    nokeyw = FALSE;        /* no keywords being flagged */
  99. boolean prccont;        /* continue last procedure */
  100. int    comtype;        /* type of comment */
  101. int    psptr;            /* the stack index of the current procedure */
  102. char    pstack[PSMAX][PNAMELEN+1];    /* the procedure name stack */
  103. int    plstack[PSMAX];        /* the procedure nesting level stack */
  104. int    blklevel;        /* current nesting level */
  105. char    *defsfile = {DEFSFILE}; /* name of language definitions file */
  106. char    pname[DBUFSIZ+1];
  107.  
  108. /*
  109.  *    The language specific globals
  110.  */
  111.  
  112. char    *language = "c";    /* the language indicator */
  113. char    *l_keywds[DBUFSIZ/2];    /* keyword table address */
  114. char    *l_prcbeg;        /* regular expr for procedure begin */
  115. char    *l_combeg;        /* string introducing a comment */
  116. char    *l_comend;        /* string ending a comment */
  117. char    *l_acmbeg;        /* string introducing a comment */
  118. char    *l_acmend;        /* string ending a comment */
  119. char    *l_blkbeg;        /* string begining of a block */
  120. char    *l_blkend;        /* string ending a block */
  121. char    *l_strbeg;        /* delimiter for string constant */
  122. char    *l_strend;        /* delimiter for string constant */
  123. char    *l_chrbeg;        /* delimiter for character constant */
  124. char    *l_chrend;        /* delimiter for character constant */
  125. char    l_escape;        /* character used to escape characters */
  126. boolean    l_toplex;        /* procedures only defined at top lex level */
  127. boolean    l_onecase;        /* upper & lower case equivalent */
  128.  
  129. int    charmflag,reallnum,outlnum,procout;
  130. char    *ignoredef;        /* if set ignore this define    */
  131. int    inignore,wide;        /* if set do wide printout    */
  132.  
  133. /*
  134.  *  global variables also used by expmatch
  135.  */
  136. extern    boolean    rescaped;    /* if last character was an escape */
  137. extern    char *rstart;        /* start of the current string */
  138.  
  139. int    (*re_strncmp)(const char *, const char *, size_t);
  140.                 /* function to do string compares */
  141. extern    int strncmp();
  142. extern    int lc_strncmp();
  143.  
  144. /*
  145.  * The following table converts ASCII characters to a printed
  146.  * representation, taking care of all the TeX quoting.  N.B.: all
  147.  * single-character strings are assumed to be equivalent to the
  148.  * character for that index (i.e., printtab['c'] can't be "f").
  149.  * (This is purely for efficiency hacking.)
  150.  */
  151. char *printtab[128] = {
  152.     "\0x",   "\\^A",  "\\^B",  "\\^C",  "\\^D",  "\\^E",  "\\^F",  "\\^G",
  153.     "\\^H",  "\t",    "}}\n",  "\\^K",  "\0x",   "\\^M",  "\\^N",  "\\^O",
  154.     "\\^P",  "\\^Q",  "\\^R",  "\\^S",  "\\^T",  "\\^U",  "\\^V",  "\\^W",
  155.     "\\^X",  "\\^Y",  "\\^Z",  "\\^[",  "\\^\\!","\\^]",  "\\^\\^","\\^_",
  156.     " ",     "!",     "\\\"",  "\\#",   "\\$",   "\\%",   "\\&",   "\\'",
  157.     "(",     ")",     "*",     "+",     ",",     "\\-",   ".",     "\\/",
  158.     "0",     "1",     "2",     "3",     "4",     "5",     "6",     "7",
  159.     "8",     "9",     ":",     ";",     "\\<",   "=",     "\\>",   "?",
  160.     "@",     "A",     "B",     "C",     "D",     "E",     "F",     "G",
  161.     "H",     "I",     "J",     "K",     "L",     "M",     "N",     "O",
  162.     "P",     "Q",     "R",     "S",     "T",     "U",     "V",     "W",
  163.     "X",     "Y",     "Z",     "[",     "\\!",   "]",     "\\^",   "\\_",
  164.     "`",     "a",     "b",     "c",     "d",     "e",     "f",     "g",
  165.     "h",     "i",     "j",     "k",     "l",     "m",     "n",     "o",
  166.     "p",     "q",     "r",     "s",     "t",     "u",     "v",     "w",
  167.     "x",     "y",     "z",     "\\{",   "\\|",   "\\}",   "\\~",   "\\^?",
  168. };
  169.  
  170. /* Output a character, with translation.  Avoid side effects with this
  171.    macro! */
  172.  
  173. /*
  174.  * Output a TeX command to tab to column "col" (see tgrindmac.tex for a 
  175.  * partial explanation of the bizarre brace arrangement).
  176.  */
  177. #define tabto(col) printf(" %d @TAB\n", col);
  178.  
  179. void
  180. sinitfile()                /* send the init file to output */
  181.  
  182. {
  183.     char    cc;
  184.  
  185.     FILE    *fptr;
  186.  
  187.     if( !(fptr = fopen(INITFILE,"r"))) {
  188.         fprintf(stderr,"Can't open init file (%s)\n",INITFILE);
  189.         exit(1);
  190.     }
  191.  
  192.     while( (cc = getc(fptr)) != -1) fputc(cc, outfptr);
  193.  
  194.     fclose(fptr);
  195. }
  196.  
  197. void    
  198. outchar(cc)            /* output the char    */
  199.     char     cc;
  200.  
  201. {
  202.     if((cc == '(') || (cc == ')') || (cc == '\\'))
  203.         putchar('\\');
  204.     if(cc == '\n')  {
  205.         outlnum++;
  206.         modechange(0);
  207.         if(!(outlnum % 10) && !procout) {
  208.         printf(" (%d) @N ",reallnum);
  209.             if(incomm)
  210.              printf("@C ");
  211.         }
  212.         procout = 0;
  213.         printf("@NL");
  214.     }
  215.     putchar(cc);
  216. }
  217.  
  218. int
  219. outpsstring(what)            /* output a postscript string */
  220.     char *what;
  221.  
  222. {
  223.     char    cc;
  224.     int    len,x;
  225.  
  226.     len = strlen(what);
  227.  
  228.         printf(" (");
  229.         for(x=0; x < len; x++)  {
  230.         cc = *(what + x);
  231.         if( (cc == '(') || (cc == ')') || (cc == '\\'))
  232.              putchar('\\');
  233.         putchar(cc);
  234.         }
  235.         printf(") ");
  236.     return(0);
  237. }
  238.  
  239. int
  240. modechange(type)            /* purge the current string if any */
  241.     int    type;            /* close out the mode string       */
  242.  
  243.  
  244. {
  245. static    int    oldtype;
  246.  
  247.     if(charmflag)  {
  248.         switch (oldtype) {
  249.     
  250.         case _SMODE : 
  251.             printf(") @S\n");
  252.             break;
  253.         case _SHMODE :
  254.             printf(") @SH\n");
  255.             break;
  256.         case _KMODE :
  257.             printf(") @K\n");
  258.             break;
  259.         case _CMODE :
  260.             printf(") @C\n");
  261.             break;
  262.         case _NMODE :
  263.             printf(") @N\n");
  264.             break;
  265.         default :;
  266.         }            /* end switch */
  267.     }        /* end if        */
  268.     if(type) 
  269.         oldtype = type;
  270.     charmflag = 0;
  271.     return(0);
  272. }
  273.  
  274. void
  275. charmode()            /* begin char mode        */
  276. {
  277.     if(!charmflag) {
  278.         printf(" (");
  279.         charmflag = -1;
  280.     }
  281. }
  282.  
  283. main(argc, argv)
  284.     int argc;
  285.     char *argv[];
  286. {
  287.     char *fname = "", *p;
  288.     char buf[DBUFSIZ];
  289.     char strings[2 * DBUFSIZ];
  290.     char defs[2 * DBUFSIZ];
  291. #ifdef    MSDOS
  292.     struct tm *tmstr;
  293. #else
  294.     struct stat stbuf;
  295. #endif
  296.     FILE    *realfptr;
  297.     int    twomode;
  298.  
  299.     twomode=0;
  300.         realfptr = stdin;
  301.     sinitfile();            /* send the init file    */
  302.  
  303.     argc--, argv++;
  304.     do {
  305.     register char *cp;
  306.     register int i;
  307.  
  308.     if (argc > 0) {
  309.         if (!strcmp(argv[0], "-h")) {
  310.         if (argc == 1) {
  311.             printf("() @Head\n");
  312.             argc--; argv++;
  313.             goto rest;
  314.         }
  315.         putstr( argv[1] );
  316.         printf( "@Head \n" );
  317.         argc--, argv++;
  318.         argc--, argv++;
  319.         if (argc > 0)
  320.             continue;
  321.         goto rest;
  322.         }
  323.       
  324.         /* check for ignore def    */
  325.         if(!strcmp(argv[0],"-id")) {
  326.         ignoredef = argv[1];
  327.         argc--; argv++;
  328.         argc--; argv++;
  329.         continue;
  330.         }
  331.  
  332.             /* -wide for wide 132 column printouts */
  333.         if(!strcmp(argv[0],"-wide")) {
  334.         wide = -1;
  335.         argc--; argv++;
  336.         continue;
  337.         }
  338.  
  339.            /* -2 2 pages per physical page    */
  340.         if(!strcmp(argv[0],"-2")) {
  341.         twomode = -1;
  342.         argc--; argv++;
  343.         continue;
  344.         }
  345.  
  346.         /* take input from the standard place */
  347.         if (!strcmp(argv[0], "-")) {
  348.         argc = 0;
  349.         realfptr = stdin;
  350.         goto rest;
  351.         }
  352.  
  353.         /* indicate no keywords */
  354.         if (!strcmp(argv[0], "-n")) {
  355.         nokeyw++;
  356.         argc--, argv++;
  357.         continue;
  358.         }
  359.  
  360.         /* specify the language */
  361.         if (!strncmp(argv[0], "-l", 2)) {
  362.         language = argv[0]+2;
  363.         argc--, argv++;
  364.         continue;
  365.         }
  366.  
  367.         /* specify the language description file */
  368.         if (!strncmp(argv[0], "-d", 2)) {
  369.         defsfile = argv[1];
  370.         argc--, argv++;
  371.         argc--, argv++;
  372.         continue;
  373.         }
  374.  
  375.         /* open the file for input */
  376.         if ((realfptr = fopen(argv[0], "r")) == NULL) {
  377.         fprintf(stderr,"Error: fopen\n");
  378.         exit(1);
  379.         }
  380.  
  381.         fname = argv[0];
  382.         argc--, argv++;
  383.     }
  384.     rest:
  385.  
  386.     /*
  387.      *  get the  language definition from the defs file
  388.      */
  389.     i = tgetent (defs, language, defsfile);
  390.     if (i == 0) {
  391.         fprintf (stderr, "no entry for language %s\n", language);
  392.         exit (0);
  393.     } else  if (i < 0) {
  394.         fprintf (stderr,  "cannot find vgrindefs file %s\n", defsfile);
  395.         exit (0);
  396.     }
  397.     p = strings;
  398.     if (tgetstr ("kw", &p) == NIL)
  399.         nokeyw = TRUE;
  400.     else  {
  401.         char **cpp;
  402.  
  403.         cpp = l_keywds;
  404.         cp = strings;
  405.         while (*cp) {
  406.         while (*cp == ' ' || *cp =='\t')
  407.             *cp++ = NULL;
  408.         if (*cp)
  409.             *cpp++ = cp;
  410.         while (*cp != ' ' && *cp  != '\t' && *cp)
  411.             cp++;
  412.         }
  413.         *cpp = NIL;
  414.     }
  415.     p = buf;
  416.     l_prcbeg = convexp (tgetstr ("pb", &p));
  417.     p = buf;
  418.     l_combeg = convexp (tgetstr ("cb", &p));
  419.     p = buf;
  420.     l_comend = convexp (tgetstr ("ce", &p));
  421.     p = buf;
  422.     l_acmbeg = convexp (tgetstr ("ab", &p));
  423.     p = buf;
  424.     l_acmend = convexp (tgetstr ("ae", &p));
  425.     p = buf;
  426.     l_strbeg = convexp (tgetstr ("sb", &p));
  427.     p = buf;
  428.     l_strend = convexp (tgetstr ("se", &p));
  429.     p = buf;
  430.     l_blkbeg = convexp (tgetstr ("bb", &p));
  431.     p = buf;
  432.     l_blkend = convexp (tgetstr ("be", &p));
  433.     p = buf;
  434.     l_chrbeg = convexp (tgetstr ("lb", &p));
  435.     p = buf;
  436.     l_chrend = convexp (tgetstr ("le", &p));
  437.     l_escape = '\\';
  438.     l_onecase = tgetflag ("oc");
  439.     if ( l_onecase )
  440.         re_strncmp = lc_strncmp;
  441.     else
  442.         re_strncmp = strncmp;
  443.     l_toplex = tgetflag ("tl");
  444.  
  445.     /* initialize the program */
  446.  
  447.     incomm = FALSE;
  448.     instr = FALSE;
  449.     inchr = FALSE;
  450.     rescaped = FALSE;
  451.     blklevel = 0;
  452.     for (psptr=0; psptr<PSMAX; psptr++) {
  453.         pstack[psptr][0] = NULL;
  454.         plstack[psptr] = 0;
  455.     }
  456.     psptr = -1;
  457. #ifndef    MSDOS
  458. #ifdef AMIGA
  459.     /* SAS's libraries don't return the current date if you
  460.      * ask for the modification date of stdin...
  461.      */
  462.     time(&stbuf.st_mtime);
  463.     cp = ctime(&stbuf.st_mtime);
  464. #else
  465.     fstat(fileno(stdin), &stbuf);
  466.     cp = ctime(&stbuf.st_mtime);
  467. #endif /* Amiga */
  468. #else
  469.     cp = asctime(tmstr = localtim(NULL));
  470. #endif
  471.     cp[10] = '\0';
  472.     cp[16] = '\0';
  473.     cp[24] = '\0';
  474.  
  475.     putstr(fname);
  476.     putstr(cp+11);
  477.     sprintf(buf,"%s %s",cp+4,cp+20);
  478.     putstr(buf);
  479.     printf("@FILE \n");
  480.     if(twomode)
  481.        printf("@DO2\n");        /* order here is important */
  482.     if(wide)
  483.        printf("@WIDE \n");        /* must come after @DO2    */
  484.     printf("@NEWPAGE\n");        /* force the page setup */
  485.     /*
  486.      *    MAIN LOOP!!!
  487.      */
  488.     outlnum = reallnum = 0;
  489.     modechange(_SHMODE);            /* set the show mode */
  490.     while (1) {
  491.         fgets(buf, sizeof buf, realfptr);
  492.         if(feof(realfptr)) {
  493.         fclose(realfptr); 
  494.         break;
  495.         }
  496.         reallnum++;
  497.         if(ignoredef)  {
  498.         if(inignore)  {
  499.                 if(!strncmp(buf,"#endif",6))  
  500.                 inignore = 0;
  501.             continue;
  502.         }
  503.         if(!(strncmp(buf,"#ifdef",6))) {
  504. #ifdef    DEBUG
  505.         fprintf(stderr,"Examining (%s)\n",buf+strlen(buf)-strlen(ignoredef)-1);
  506. #endif
  507.             if(!(strncmp(buf+strlen(buf)-strlen(ignoredef)-1,
  508.                 ignoredef,strlen(ignoredef)))) {
  509.             inignore = -1;
  510.             continue;
  511.             }
  512.         }
  513.         }
  514.     
  515.         cp = buf;
  516.         if (*cp == '\f') {
  517.         printf("@NEXTPAGE \n");
  518.         cp++;
  519.         if (*cp == '\n')/* some people like ^Ls on their own line */
  520.             continue;
  521.         }
  522.         prccont = FALSE;
  523.         putScp(cp);
  524.         if (prccont && (psptr >= 0)) {
  525.         putstr(pstack[psptr]);
  526.         printf("@PROCC\n");
  527.         procout = -1;
  528.         }
  529. #ifdef DEBUG
  530.         fprintf (stderr,"com %o str %o chr %o ptr %d\n", incomm, instr, inchr, psptr);
  531. #endif
  532.     }
  533.         if(argc <= 0) break;
  534.     printf("@FLUSHPAGE\n");
  535.     } while (argc > 0);
  536.     printf("@FLUSHPAGE\n%c",4);
  537.     exit(0);
  538. }
  539.  
  540. #define isidchr(c) (isalnum(c) || (c) == '_')
  541.  
  542. void
  543. putScp(os)
  544.     char *os;
  545. {
  546.     register char *s;            /* pointer to unmatched string */
  547.     char *comptr;            /* start of a comment delimiter */
  548.     char *comendptr;            /* end of a comment delimiter */
  549.     char *acmptr;            /* start of an alt. comment delimiter */
  550.     char *acmendptr;            /* end of an alt. comment delimiter */
  551.     char *strptr;            /* start of a string delimiter */
  552.     char *strendptr;            /* end of a string delimiter */
  553.     char *chrptr;            /* start of a char. const delimiter */
  554.     char *chrendptr;            /* end of a char. const delimiter */
  555.     char *blksptr;            /* start of a lexical block start */
  556.     char *blksendptr;            /* end of a lexical block start */
  557.     char *blkeptr;            /* start of a lexical block end */
  558.     char *blkeendptr;            /* end of a lexical block end */
  559.  
  560. #ifdef    DEBUG
  561.     fprintf(stderr,"PutScp    %s\n",os);
  562. #endif
  563.     s = os;
  564.     rstart = os;            /* remember the start for expmatch */
  565.     rescaped = FALSE;
  566.     if (nokeyw || incomm || instr)
  567.     goto skip;
  568.     if (isproc(s)) {
  569.     modechange(0);
  570.     putstr(pname);
  571.     printf("@PROC\n");
  572.     procout = -1;
  573.     if (psptr < PSMAX) {
  574.         ++psptr;
  575.         strncpy (pstack[psptr], pname, PNAMELEN);
  576.         pstack[psptr][PNAMELEN] = NULL;
  577.         plstack[psptr] = blklevel;
  578.     }
  579.     } 
  580. skip:
  581.     do {
  582.     /* check for string, comment, blockstart, etc */
  583.     if (!incomm && !instr && !inchr) {
  584.  
  585.         blkeendptr = expmatch (s, l_blkend, &blkeptr, NIL);
  586.         blksendptr = expmatch (s, l_blkbeg, &blksptr, NIL);
  587.         comendptr = expmatch (s, l_combeg, &comptr, NIL);
  588.         acmendptr = expmatch (s, l_acmbeg, &acmptr, NIL);
  589.         strendptr = expmatch (s, l_strbeg, &strptr, NIL);
  590.         chrendptr = expmatch (s, l_chrbeg, &chrptr, NIL);
  591.  
  592.         /* start of a comment? */
  593.         if (comptr != NIL
  594.           && (strptr  == NIL || comptr < strptr)
  595.           && (acmptr  == NIL || comptr < acmptr)
  596.           && (chrptr  == NIL || comptr < chrptr)
  597.           && (blksptr == NIL || comptr < blksptr)
  598.           && (blkeptr == NIL || comptr < blkeptr)) {
  599.             putKcp (s, comptr-1, FALSE);
  600.             modechange(0);
  601.             printf("@C\n");
  602.             modechange(_SHMODE);
  603.             s = comendptr;
  604.             putKcp (comptr, comendptr-1, FALSE);
  605.             incomm = TRUE;
  606.             comtype = STANDARD;
  607.             continue;
  608.         }
  609.  
  610.         /* start of an alternate-form comment? */
  611.         if (acmptr != NIL
  612.           && (strptr  == NIL || acmptr < strptr)
  613.           && (chrptr  == NIL || acmptr < chrptr)
  614.           && (blksptr == NIL || acmptr < blksptr)
  615.           && (blkeptr == NIL || acmptr < blkeptr)) {
  616.             putKcp (s, acmptr-1, FALSE);
  617.             modechange(0);
  618.             printf("@C\n");
  619.             modechange(_SHMODE);
  620.             s = acmendptr;
  621.             putKcp (acmptr, acmendptr, FALSE);
  622.             incomm = TRUE;
  623.             comtype = ALTERNATE;
  624.             continue;
  625.         }
  626.  
  627.         /* start of a string? */
  628.         if (strptr != NIL
  629.           && (chrptr  == NIL || strptr < chrptr)
  630.           && (blksptr == NIL || strptr < blksptr)
  631.           && (blkeptr == NIL || strptr < blkeptr)) {
  632.             putKcp (s, strptr-1, FALSE);
  633.             modechange(_SMODE);
  634.             s = strendptr;
  635.             putKcp (strptr,strendptr-1, FALSE);
  636.             instr = TRUE;
  637.             continue;
  638.         }
  639.  
  640.         /* start of a character string? */
  641.         if (chrptr != NIL
  642.           && (blksptr == NIL || chrptr < blksptr)
  643.           && (blkeptr == NIL || chrptr < blkeptr)) {
  644.             putKcp (s, chrptr-1, FALSE);
  645.             modechange(_SMODE);
  646.             s = chrendptr;
  647.             putKcp (chrptr, chrendptr-1, FALSE);
  648.             inchr = TRUE;
  649.             continue;
  650.         }
  651.  
  652.         /* end of a lexical block */
  653.         if (blkeptr != NIL) {
  654.         if (blksptr == NIL || blkeptr < blksptr) {
  655.             putKcp (s, blkeendptr - 1, FALSE);
  656.             s = blkeendptr;
  657.             blklevel--;
  658.             if (psptr >= 0 && plstack[psptr] >= blklevel) {
  659.  
  660.             /* end of current procedure */
  661.             blklevel = plstack[psptr];
  662.  
  663.             /* see if we should print the last proc name */
  664.             if (--psptr >= 0)
  665.                 prccont = TRUE;
  666.             else
  667.                 psptr = -1;
  668.             }
  669.             continue;
  670.         }
  671.         }
  672.  
  673.         /* start of a lexical block */
  674.         if (blksptr != NIL) {
  675.         putKcp (s, blksendptr - 1, FALSE);
  676.         s = blksendptr;
  677.         blklevel++;
  678.         continue;
  679.         }
  680.  
  681.     /* check for end of comment */
  682.     } else if (incomm) {
  683.         if ((comendptr = expmatch( s,
  684.                        comtype==STANDARD? l_comend : l_acmend,
  685.                            NIL, NIL)) != NIL) {
  686.         putKcp (s, comendptr-1, TRUE);
  687.         s = comendptr;
  688.         incomm = FALSE;
  689.         modechange(0);
  690.         printf(" @CE\n");
  691.         modechange(_SHMODE);
  692.         } else {
  693.         comptr = s;
  694.         s += strlen(s);
  695.         putKcp (comptr, s-1, TRUE);
  696.         }
  697.         continue;
  698.  
  699.     /* check for end of string */
  700.     } else if (instr) {
  701.         if ((strendptr = expmatch (s, l_strend, NIL, NIL)) != NIL) {
  702.         putKcp (s, strendptr-1, TRUE);
  703.         s = strendptr;
  704.         instr = FALSE;
  705.         modechange(_SHMODE);
  706.         
  707.         } else {
  708.         strptr = s;
  709.         s += strlen(s);
  710.         putKcp (strptr, s-1, TRUE);
  711.         }
  712.         continue;
  713.  
  714.     /* check for end of character string */
  715.     } else if (inchr) {
  716.         if ((chrendptr = expmatch (s, l_chrend, NIL, NIL)) != NIL) {
  717.         putKcp (s, chrendptr-1, TRUE);
  718.         s = chrendptr;
  719.         inchr = FALSE;
  720.         modechange(_SHMODE);
  721.         } else {
  722.         chrptr = s;
  723.         s += strlen(s);
  724.         putKcp (chrptr, s-1, TRUE);
  725.         }
  726.         continue;
  727.     }
  728.  
  729.     /* print out the line */
  730.     chrptr = s;
  731.     s += strlen(s);
  732.     putKcp (chrptr, s-1, FALSE);
  733.  
  734.     } while (*s);
  735. }
  736.  
  737. void
  738. putKcp(start, end, nix)
  739.     register char *start;    /* start of string to write */
  740.     register char *end;    /* end of string to write */
  741.     register boolean nix;    /* true if we should force nokeyw */
  742. {
  743.     register int i, c;
  744.  
  745.     if (nokeyw)
  746.         nix = TRUE;
  747.  
  748.     while (start <= end) {
  749.         c = *start++;
  750.         /* take care of nice tab stops */
  751.         if (c == '\t') {
  752.             while (start <= end && *start == '\t')
  753.                 start++;
  754.             modechange(0);
  755.             tabto(width(rstart, start));
  756.             continue;
  757.         }
  758.         if (!nix && (c == '#' || isidchr(c))) {/* potential keyword */
  759.             start--;
  760.             if (start == rstart || !isidchr(start[-1])) {
  761.                 i = iskw(start);
  762.                 if (i > 0) {
  763.                     modechange(_KMODE);
  764.                     printf(" (");
  765.                     charmflag = -1;
  766.                     while (--i >= 0) {
  767.                         c = *start++;
  768.                         outchar(c);
  769.                     }
  770.                     modechange(_SHMODE);
  771.                     continue;
  772.                 }
  773.             }
  774.             start++;
  775.         }
  776.         charmode();
  777.         outchar(c);
  778.     }
  779. }
  780.  
  781.  
  782. int
  783. width(s, os)
  784.     register char *s, *os;
  785. {
  786.     register int i = 0, c;
  787.  
  788.     while (s < os) {
  789.         c = *s++;
  790.         if (c == '\t') {
  791.             i = (i + 8) &~ 7;
  792.             continue;
  793.         }
  794.         if (c < ' ')
  795.             i += 2;
  796.         else
  797.             i++;
  798.     }
  799.     return (i);
  800. }
  801.  
  802. /* output a string, escaping special characters */
  803. void
  804. putstr(cp)
  805.     register char *cp;
  806. {
  807.     outpsstring(cp);
  808. }
  809.  
  810. /*
  811.  *    look for a process beginning on this line
  812.  */
  813. boolean
  814. isproc(s)
  815.     char *s;
  816. {
  817.     pname[0] = NULL;
  818.     if ((!l_toplex || blklevel == 0)
  819.         && expmatch(s, l_prcbeg, NIL, pname) != NIL)
  820.         return (TRUE);
  821.     return (FALSE);
  822. }
  823.  
  824.  
  825. /*  iskw -    check to see if the next word is a keyword
  826.  */
  827.  
  828. int
  829. iskw(s)
  830.     register char *s;
  831. {
  832.     register char **ss = l_keywds;
  833.     register int i = 1;
  834.     register char *cp = s;
  835.     register int firstc = *s;
  836.  
  837.     while (++cp, isidchr(*cp))
  838.         i++;
  839.     while (cp = *ss++) {
  840.         if (!l_onecase && firstc != *cp)
  841.             continue;
  842.         if ((*re_strncmp)(s, cp, i) == 0 && !isidchr(cp[i]))
  843.             return (i);
  844.     }
  845.     return (0);
  846. }
  847.